from PyQt5.QtWidgets import QTableWidgetItem, QLabel, QHBoxLayout, QWidget, QMenu, QMessageBox
from PyQt5.QtCore import QTimer, Qt, QPoint, QThread, pyqtSignal

import time
import queue

from common.logger import logger
from common.retcode import RetCode, TransferType, TransferStatus
from common.utils import get_file_size_str
from common.types import TransferInfo
from api.download import DownloadAction
from api.upload import UploadAction

class TransferWorker(QThread):
	triggerMessageBox = pyqtSignal(str)
	triggerRefreshTransferList = pyqtSignal(object)
	triggerRefreshFolder = pyqtSignal(object)

	def __init__(self, q, callback):
		super(TransferWorker, self).__init__()
		self._queue = q
		self.callback = callback

	def run(self):
		while True:
			item = self._queue.get()
			if item is None:
				break

			if self.callback is not None:
				self.callback(item)
			self._queue.task_done()

	def emitMessageBox(self, params):
		self.triggerMessageBox.emit(params)

	def emitRefreshTransferList(self, params):
		self.triggerRefreshTransferList.emit(params)

	def emitRefreshFolder(self, params):
		self.triggerRefreshFolder.emit(params)

class MainTransferTable():
	def __init__(self, main_win):
		self._main_win = main_win

		self.initWidgets()

		self._queue = queue.Queue()
		self._worker = TransferWorker(self._queue, self.transfer_file)
		self._worker.start()
		self._worker.triggerMessageBox.connect(lambda x: QMessageBox.information(self._main_win, "提示", x))
		self._worker.triggerRefreshTransferList.connect(self.refresh_transfer_list)
		self._worker.triggerRefreshFolder.connect(lambda x: self._main_win._files_table.getFolder(x, True))

	def initWidgets(self):
		self._main_win.pushButtonAllTransferStart.clicked.connect(self.onClickedAllTransferStart)
		self._main_win.pushButtonAllTransferPause.clicked.connect(self.onClickedAllTransferPause)
		self._main_win.pushButtonAllTransferDelete.clicked.connect(self.onClickedAllTransferDelete)
		self._main_win.pushButtonDeleteCompletionTransfer.clicked.connect(self.onClickedDeleteCompletionTransfer)

		self._main_win.tableWidgetTransfer.horizontalHeader().setFixedHeight(50) ##设置表头高度
		self._main_win.tableWidgetTransfer.horizontalHeader().resizeSection(0, 300) #设置列的宽度
		self._main_win.tableWidgetTransfer.horizontalHeader().resizeSection(1, 100) #设置列的宽度
		self._main_win.tableWidgetTransfer.horizontalHeader().resizeSection(2, 200) #设置列的宽度
		self._main_win.tableWidgetTransfer.horizontalHeader().resizeSection(3, 150) #设置列的宽度
		self._main_win.tableWidgetTransfer.horizontalHeader().resizeSection(4, 100) #设置列的宽度

		self._main_win.tableWidgetTransfer.horizontalHeader().setSectionsClickable(False) #可以禁止点击表头的列

		self._main_win.tableWidgetTransfer.setContextMenuPolicy(Qt.CustomContextMenu)  #允许右键产生子菜单
		self._main_win.tableWidgetTransfer.customContextMenuRequested.connect(self.generateTransferOptMenu)  #右键菜单

	########################################################################
	def stopWorking(self):
		self.onClickedAllTransferPause()

	def onShutDown(self):
		self.stopWorking()
		self._queue.put(None)
		self._worker.wait()
		print('TransferWorker stop')

	########################################################################

	def onClickedAllTransferStart(self):
		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is None:
			return

		for transfer_info in transfer_list:
			if transfer_info.status == TransferStatus.FAILED or transfer_info.status == TransferStatus.PAUSED:
				transfer_info.status = TransferStatus.RESUMING
				self.refresh_transfer_list(transfer_list)
				self._queue.put(transfer_info)

	def onClickedAllTransferPause(self):
		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is None:
			return

		for transfer_info in transfer_list:
			if transfer_info.status == TransferStatus.TRANSFERING:
				transfer_info.status = TransferStatus.PAUSING
			elif transfer_info.status == TransferStatus.WAITING or transfer_info.status == TransferStatus.RESUMING:
				transfer_info.status = TransferStatus.PAUSED
		self.refresh_transfer_list(transfer_list)

	def onClickedAllTransferDelete(self):
		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is None:
			return
		to_delete = []
		for transfer_info in transfer_list:
			if transfer_info.status == TransferStatus.TRANSFERING:
				transfer_info.status = TransferStatus.DELETING
			else:
				to_delete.append(transfer_info)
		for transfer_info in to_delete:
			transfer_list.remove(transfer_info)
		
		self._main_win._sess_wp.save_config()
		self.refresh_transfer_list(transfer_list)

	def onClickedDeleteCompletionTransfer(self):
		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is None:
			return
		to_delete = []
		for transfer_info in transfer_list:
			if transfer_info.status == TransferStatus.SUCCESS:
				to_delete.append(transfer_info)

		for transfer_info in to_delete:
			transfer_list.remove(transfer_info)
		
		self._main_win._sess_wp.save_config()
		self.refresh_transfer_list(transfer_list)

	def generateTransferOptMenu(self, pos):
		row_num = -1
		for idx in self._main_win.tableWidgetTransfer.selectionModel().selection().indexes():
			row_num = idx.row()

		if row_num < 0:
			return

		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is None:
			return

		if row_num >= len(transfer_list):
			return

		transfer_info = transfer_list[row_num]
		if transfer_info.status == TransferStatus.PAUSING or transfer_info.status == TransferStatus.DELETING:
			# 传输状态处于中间过程，不作任何操作
			return

		menu = QMenu()
		
		item1 = None
		item2 = None
		if transfer_info.status == TransferStatus.TRANSFERING:
			item2 = menu.addAction(u"暂停")
		elif transfer_info.status == TransferStatus.FAILED or transfer_info.status == TransferStatus.PAUSED:
			item1 = menu.addAction(u"开始")

		item3 = menu.addAction(u"删除")

		action = menu.exec_(self._main_win.tableWidgetTransfer.mapToGlobal(pos + QPoint(0, 30)))
		if (action == item1) and (item1 is not None):
			print('press start')
			transfer_info.status = TransferStatus.RESUMING
			self.refresh_transfer_list(transfer_list)
			self._queue.put(transfer_info)

		elif (action == item2) and (item2 is not None):
			transfer_info.status = TransferStatus.PAUSING
			# self._main_win._sess_wp.save_config()
			self.refresh_transfer_list(transfer_list)
			
		elif action == item3:
			if transfer_info.status == TransferStatus.TRANSFERING:
				transfer_info.status = TransferStatus.DELETING
			else:
				transfer_list.remove(transfer_info)
				self._main_win._sess_wp.save_config()
			self.refresh_transfer_list(transfer_list)
		else:
			return

	def add_download_task(self, file_info):
		setting_info = self._main_win._sess_wp.get_setting_info()
		if not setting_info:
			QMessageBox.information(self._main_win, "提示", "无法找到下载设置")
			return False

		transfer_info = TransferInfo()
		transfer_info.name = file_info.name
		transfer_info.path = setting_info.downDir
		transfer_info.type = TransferType.DOWNLOAD
		transfer_info.fid = file_info.id
		transfer_info.ftype = file_info.ftype
		transfer_info.isFolder = file_info.isFolder

		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is not None:
			transfer_list.append(transfer_info)
			self._main_win._sess_wp.save_config()
			self.refresh_transfer_list(transfer_list)
		else:
			QMessageBox.information(self._main_win, "提示", "传输队列没有初始化")
			return False

		self._queue.put(transfer_info)
		return True

	def download_file(self, transfer_info):
		code = None
		msg = None
		donwload_action = DownloadAction(self._main_win._sess_wp)
		if transfer_info.isFolder:
			code, msg = donwload_action.down_dirzip_by_id(transfer_info, callback=self.on_show_transfer_progress)
		else:
			code, msg = donwload_action.down_file_by_id(transfer_info, callback=self.on_show_transfer_progress)

		if code != RetCode.SUCCESS:
			transfer_info.status = TransferStatus.FAILED
		else:
			if transfer_info.nowSize >= transfer_info.totalSize and transfer_info.totalSize > 0:
				transfer_info.status = TransferStatus.SUCCESS
			else:
				transfer_info.status = TransferStatus.PAUSED
		if msg and len(msg) > 0:
			self._worker.emitMessageBox(msg)

		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is not None:
			if transfer_info.status == TransferStatus.DELETING:
				transfer_list.remove(transfer_info)
			self._main_win._sess_wp.save_config()
			self._worker.emitRefreshTransferList(transfer_list)

	def add_upload_task(self, transfer_info):

		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is not None:
			transfer_list.append(transfer_info)
			self._main_win._sess_wp.save_config()
			self.refresh_transfer_list(transfer_list)
		else:
			QMessageBox.information(self._main_win, "提示", "传输队列没有初始化")
			return False

		self._queue.put(transfer_info)
		return True

	def upload_file(self, transfer_info):
		code = None
		msg = None

		upload_action = UploadAction(self._main_win._sess_wp)
		if transfer_info._upload_type == 0:
			code, msg = upload_action.upload_dir(transfer_info, callback=self.on_show_transfer_progress)
		else:
			code, msg = upload_action.upload_files(transfer_info, callback=self.on_show_transfer_progress)

		if code != RetCode.SUCCESS:
			transfer_info.status = TransferStatus.FAILED
		else:
			transfer_info.status = TransferStatus.SUCCESS
		if msg and len(msg) > 0:
			self._worker.emitMessageBox(msg)

		transfer_list = self._main_win._sess_wp.get_transfer_list()
		if transfer_list is not None:
			if transfer_info.status == TransferStatus.DELETING:
				transfer_list.remove(transfer_info)
			self._main_win._sess_wp.save_config()
			self._worker.emitRefreshTransferList(transfer_list)
			if transfer_info.type == TransferType.UPLOAD:
				self._worker.emitRefreshFolder(transfer_info.fid)

	def transfer_file(self, transfer_info):
		if transfer_info.type == TransferType.DOWNLOAD:
			self.download_file(transfer_info)
		else:
			self.upload_file(transfer_info)

	def on_show_transfer_progress(self, transfer_info, now_size):
		to_continue = True
		
		now = time.perf_counter()

		delta_size = now_size - transfer_info.nowSize
		transfer_info.nowSize = now_size

		delta_seconds = now - transfer_info.lastTick
		transfer_info.lastTick = now

		if delta_seconds > 0 and delta_size > 0:
			transfer_info.speed = delta_size / delta_seconds
		elif transfer_info.speed is None:
			transfer_info.speed = 0
		
		if transfer_info.status == TransferStatus.PAUSING:
			transfer_info.status = TransferStatus.PAUSED
			to_continue = False
		elif transfer_info.status == TransferStatus.DELETING:
			to_continue = False
		else:
			transfer_info.status = TransferStatus.TRANSFERING
		# self._main_win._sess_wp.save_config()
		
		transfer_list = self._main_win._sess_wp.get_transfer_list()
		self._worker.emitRefreshTransferList(transfer_list)					
		
		return to_continue

	def refresh_transfer_list(self, transfer_list):
		self._main_win.tableWidgetTransfer.setRowCount(len(transfer_list))
		row = 0
		for transfer_info in transfer_list:

			fileIconLabel = self._main_win.getFileIconLabel(transfer_info)

			fileNameLabel = QLabel()
			fileNameLabel.setText(transfer_info.name)
			fileNameLayout = QHBoxLayout()
			fileNameLayout.setAlignment(Qt.AlignLeft)
			fileNameLayout.addWidget(fileIconLabel)
			fileNameLayout.addWidget(fileNameLabel)
			fileNameWidget = QWidget()
			fileNameWidget.setLayout(fileNameLayout)

			transferTypeItem = QTableWidgetItem('下载' if transfer_info.type == TransferType.DOWNLOAD else '上传')
			transferTypeItem.setTextAlignment(Qt.AlignCenter)

			progressItem = None
			if transfer_info.type == TransferType.DOWNLOAD:
				if transfer_info.totalSize > 0:
					pcnt = (transfer_info.nowSize * 10000 // transfer_info.totalSize) / 100
					progressItem = QTableWidgetItem(f'{pcnt}%')
				else:
					nowSize = get_file_size_str(transfer_info.nowSize)
					progressItem = QTableWidgetItem(f'{nowSize}')
			else:
				pcnt = 0
				if transfer_info.totalSize > 0:
					pcnt = (transfer_info.nowSize * 10000 // transfer_info.totalSize) / 100
				progressItem = QTableWidgetItem(f'{transfer_info.index}/{len(transfer_info.upload_info_list)} ({pcnt}%)')

			progressItem.setTextAlignment(Qt.AlignCenter)

			speed = get_file_size_str(transfer_info.speed)
			speedItem = QTableWidgetItem(f'{speed}/s' if speed else '未知')
			speedItem.setTextAlignment(Qt.AlignCenter)

			status = ''
			if transfer_info.status == TransferStatus.FAILED:
				status = '传输失败'
			elif transfer_info.status == TransferStatus.WAITING:
				status = '准备传输'
			elif transfer_info.status == TransferStatus.TRANSFERING:
				status = '传输中'
			elif transfer_info.status == TransferStatus.SUCCESS:
				status = '传输完成'
			elif transfer_info.status == TransferStatus.PAUSING:
				status = '正在停止'
			elif transfer_info.status == TransferStatus.PAUSED:
				status = '已停止'
			elif transfer_info.status == TransferStatus.DELETING:
				status = '准备删除'
			elif transfer_info.status == TransferStatus.RESUMING:
				status = '恢复传输'
			statusItem = QTableWidgetItem(status)
			statusItem.setTextAlignment(Qt.AlignCenter)

			pathItem = QTableWidgetItem(transfer_info.path)
			pathItem.setTextAlignment(Qt.AlignCenter)

			self._main_win.tableWidgetTransfer.setCellWidget(row, 0, fileNameWidget)
			self._main_win.tableWidgetTransfer.setItem(row, 1, transferTypeItem)
			self._main_win.tableWidgetTransfer.setItem(row, 2, progressItem)
			self._main_win.tableWidgetTransfer.setItem(row, 3, speedItem)
			self._main_win.tableWidgetTransfer.setItem(row, 4, statusItem)
			self._main_win.tableWidgetTransfer.setItem(row, 5, pathItem)

			row += 1
